package{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFormat;

	public class UI extends TextField{
		
		public static function layout(sprite:Sprite,align:String="L",width:int=0,spacing:int=10,leading:int=10):void{
			for(var x:int=0,y:int=0,h:int=0,i:int=0,j:int=0,n:int=sprite.numChildren-1;i<=n;i++){
				var child:DisplayObject=sprite.getChildAt(i);
				child.x=x;
				child.y=y;
				x+=child.width;
				if(h<child.height){
					h=child.height;
				}
				var end:Boolean=i==n;
				if(!end&&width>0){
					child=sprite.getChildAt(i+1);
					if(x+spacing+child.width>width){
						end=true;
					}
				}
				if(end&&align!="TL"){
					for(;j<=i;j++){
						var alignChild:DisplayObject=sprite.getChildAt(j);
						if(align==null||align=="T"||align=="B"||align=="center"){
							alignChild.x+=(width-x)>>1;
						}
						else if(align=="R"||align=="TR"||align=="BR"||align=="right"){
							alignChild.x+=width-x;
						}
						if(align==null||align=="L"||align=="R"){
							alignChild.y+=(h-alignChild.height)>>1;
						}
						else if(align=="B"||align=="BL"||align=="BR"){
							alignChild.y+=h-alignChild.height;
						}
					}
				}
				if(i<n){
					if(end){
						y+=leading+h;
						x=h=0;
					}
					else{
						x+=spacing;
					}
				}
			}
		}
		
		public static function createTextInput(width:int,text:String="",maxChars:int=0,restrict:String=null):TextField{
			return new Input(width,16,text,false,maxChars,restrict);
		}
		
		public static function createTextArea(width:int,height:int,text:String="",maxChars:int=0,restrict:String=null):TextField{
			return new Input(width,height,text,true,maxChars,restrict);
		}
		
		public static function createLabel(data:Object,align:String=null,width:int=0,height:int=0):UI{
			return new Label(data,align,width,height);
		}
		
		public static function createButton(data:String,onclick:Function=null,align:String=null,width:int=0,height:int=0):UI{
			return new Button(data,onclick,align,width,height);
		}
		
		public static function createCheckBox(data:String,oncheck:Function=null,checked:Boolean=false,align:String=null,width:int=0,height:int=0):UI{
			return new CheckBox(data,oncheck,checked,align,width,height);
		}
		
		public static function createRadioGroup(data:Array,oncheck:Function=null,checked:int=0,tabWidth:int=0,align:String=null,width:int=0,height:int=0):UI{
			return new RadioGroup(data,oncheck,checked,tabWidth,align,width,height);
		}
		
		public static function createComboBox(data:Array,oncheck:Function=null,checked:int=0,width:int=0,height:int=0):UI{
			return new ComboBox(data,oncheck,checked,width,height);
		}
		
		public static function createList(data:Array,oncheck:Function=null,width:int=0,height:int=0,checked:int=-1):UI{
			return new List(data,oncheck,width,height,checked);
		}
		
		public static function createTree(data:Array,oncheck:Function=null,width:int=0,height:int=0,expanded:Object=null):UI{
			return new Tree(data,oncheck,width,height,expanded||{});
		}
		
		protected var textFormat:TextFormat=new TextFormat("simsun");
		public function UI(data:Object,width:int,height:int){
			_data=data;
			_width=width;
			_height=height;
			selectable=false;
			multiline=true;
			updateFormat();
			updateText();
			updateSize();
		}
		
		protected var _data:Object;
		public function get data():Object{return _data;}
		public function set data(data:Object):void{
			_data=data;
			updateText();
			updateSize();
		}
		
		protected var _width:int;
		override public function set width(value:Number):void{
			_width=value;
			updateSize();
		}
		
		protected var _height:int;
		override public function set height(value:Number):void{
			_height=value;
			updateSize();
		}
		
		protected function updateFormat():void{
			textFormat.leading=2;
			defaultTextFormat=textFormat;
		}
		
		protected function updateText():void{
			text=String(_data);
		}
		
		protected function updateSize():void{
			if(_width<=0||_height<=0){
				super.width=_width>0?_width:(textWidth+4);
				super.height=_height>0?_height:(textHeight+4);
			}   
			else{
				super.width=_width;
				super.height=_height;
			}
		}
	}
}
import flash.events.FocusEvent;
import flash.events.MouseEvent;
import flash.events.TextEvent;
import flash.geom.Matrix;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.ui.Mouse;
import flash.ui.MouseCursor;

function getLineIndexAtMouse(textField:TextField):int{
	var mouseY:int=textField.mouseY;
	if(mouseY<15)return textField.scrollV-1;
	var now:int=(mouseY-15)/14+textField.scrollV;
	var max:int=textField.bottomScrollV-1;
	if(now>max)now=max;
	return now;
}

function createMouseWheel(textField:TextField):void{
	textField.addEventListener(MouseEvent.MOUSE_WHEEL,onMouseEvent);
	textField.mouseWheelEnabled=false;
}

function createMouseOverOut(textField:TextField):void{
	textField.addEventListener(MouseEvent.MOUSE_OVER,onMouseEvent);
	textField.addEventListener(MouseEvent.MOUSE_OUT,onMouseEvent);
	textField.backgroundColor=0xf9f9f9;
	textField.borderColor=0xaaaaaa;
	textField.background=true;
	textField.border=true;
}

function onMouseEvent(event:MouseEvent):void{
	var textField:TextField=event.target as TextField;
	var eventType:String=event.type;
	if(eventType==MouseEvent.MOUSE_OVER){
		textField.backgroundColor=0xffffff;
		textField.borderColor=0x000000;
	}
	else if(eventType==MouseEvent.MOUSE_OUT){
		textField.backgroundColor=0xf9f9f9;
		textField.borderColor=0xaaaaaa;
	}
	else if(textField.maxScrollV>1){
		textField.scrollV+=event.delta<0?1:-1;
	}
}
	
class Input extends TextField{
	
	public function Input(width:int,height:int,text:String,multiline:Boolean,maxChars:int,restrict:String){
		defaultTextFormat=new TextFormat("simsun",null,null,null,null,null,null,null,multiline?"left":"center");
		type=TextFieldType.INPUT;
		this.text=text;
		this.width=width;
		this.height=height;
		this.maxChars=maxChars;
		this.restrict=restrict;
		this.wordWrap=multiline;
		this.multiline=multiline;
		createMouseWheel(this);
		createMouseOverOut(this);
		addEventListener(FocusEvent.FOCUS_IN,onFocusIn);
		addEventListener(FocusEvent.FOCUS_OUT,onFocusOut);
	}

	protected function onFocusIn(event:FocusEvent):void{
		textColor=0xf00000;
	}
	
	protected function onFocusOut(event:FocusEvent):void{
		textColor=0x000000;
	}
}
class Label extends UI{
	
	protected var align:String;
	protected var sizeFormat:TextFormat=new TextFormat("simsun");
	public function Label(data:Object,align:String,width:int,height:int){
		this.align=align;
		super(data,width,height);
	}
	
	override protected function updateFormat():void{
		if(align==null||align=="T"||align=="B"||align=="center"){
			textFormat.align="center";
		}
		else if(align=="R"||align=="TR"||align=="BR"||align=="right"){
			textFormat.align="right";
		}
		sizeFormat.leading=0;
		super.updateFormat();
	}
	
	override protected function updateText():void{
		text=String(_height<=0||align=="T"?_data:"\n"+_data);
	}
	
	override protected function updateSize():void{
		super.updateSize();
		if(_height>0){
			if(align==null||align=="L"||align=="R"){
				sizeFormat.size=(_height-textHeight+8)/2;
				setTextFormat(sizeFormat,0,1);
			}
			else if(align=="B"||align=="BL"||align=="BR"){
				sizeFormat.size=_height-textHeight+8;
				setTextFormat(sizeFormat,0,1);
			}
		}
	}
	
	override public function set height(height:Number):void{
		_height=height;
		updateText();
		updateSize();
	}
}
class Button extends Label{
	
	protected var onclick:Function;
	public function Button(data:Object,onclick:Function,align:String,width:int,height:int){
		this.onclick=onclick;
		createMouseOverOut(this);
		super(data,align,width,height);
		addEventListener(MouseEvent.RELEASE_OUTSIDE,onMouseEvent);
		addEventListener(MouseEvent.MOUSE_DOWN,onMouseEvent);
		addEventListener(MouseEvent.MOUSE_OVER,onMouseEvent);
		addEventListener(MouseEvent.MOUSE_OUT,onMouseEvent);
		addEventListener(MouseEvent.CLICK,onMouseEvent);
	}
	
	protected function onMouseEvent(event:MouseEvent):void{
		var eventType:String=event.type;
		if(eventType==MouseEvent.MOUSE_OVER){
			Mouse.cursor=MouseCursor.BUTTON;
		}
		else if(eventType==MouseEvent.MOUSE_OUT){
			Mouse.cursor=MouseCursor.AUTO;
		}
		else if(eventType==MouseEvent.MOUSE_DOWN){
			textColor=0xf00000;
		}
		else{
			textColor=0x000000;
			if(eventType==MouseEvent.CLICK){
				if(onclick!=null){
					onclick();
				}
			}
		}
	}
}
class CheckBox extends Label{
	
	protected var oncheck:Function;
	protected var checked:Boolean;
	
	public function CheckBox(data:Object,oncheck:Function,checked:Boolean,align:String,width:int,height:int){
		this.oncheck=oncheck;
		this.checked=checked;
		super(data,align,width,height);
		addEventListener(TextEvent.LINK,onLink);
	}
	
	override protected function updateFormat():void{
		super.updateFormat();
		textFormat.url="event:";
	}
	
	override protected function updateText():void{
		text=(checked?"\u2237":"\u25a1")+_data;
		textColor=checked?0xf00000:0x000000;
		setTextFormat(textFormat,_height>0?1:0,length);
	}
	
	protected function onLink(event:TextEvent):void{
		checked=!checked;
		updateText();
		if(oncheck!=null){
			oncheck(checked);
		}
	}
}
class RadioGroup extends Label{
	
	protected var oncheck:Function;
	protected var checked:int;
	protected var tabWidth:int;
	
	public function RadioGroup(data:Object,oncheck:Function,checked:int,tabWidth:int,align:String,width:int,height:int){
		this.oncheck=oncheck;
		this.checked=checked;
		this.tabWidth=tabWidth;
		super(data,align,width,height);
		addEventListener(TextEvent.LINK,onLink);
	}
	
	override protected function updateFormat():void{
		if(tabWidth>0){
			var tabStops:Array=[];
			var count:int=(_data as Array).length;
			var width:int=tabWidth*count-4;
			var delta:int=width/count;
			for(var i:int=0;i<count-1;i++){
				tabStops[i]=(i+1)*delta;
			}
			tabStops[i]=width;
			textFormat.tabStops=tabStops;
		}
		super.updateFormat();
	}
	
	override protected function updateText():void{
		var tabChar:String=tabWidth>0?"\t":"\u3000";
		var tabTexts:Array=_data as Array;
		var tabLength:int=tabTexts.length;
		var tabText:String="";
		for(var i:int=0;i<tabLength;i++){
			tabText+=(i==checked?"\u25ce":"\u25cb")+tabTexts[i]+tabChar;
		}
		this.text=tabText;
		var index:int=_height>0?1:0;
		for(var j:int=0;j<tabLength;j++){
			tabText=tabTexts[j];
			if(j==checked){
				textFormat.url=null;
				textFormat.color=0xf00000;
			}
			else{
				textFormat.url="event:"+j;
				textFormat.color=0x000000;
			}
			setTextFormat(textFormat,index,(index+=tabText.length+2)-1);
		}
	}
	
	protected function onLink(event:TextEvent):void{
		checked=int(event.text);
		updateText();
		if(oncheck!=null){
			oncheck(checked);
		}
	}
}
class List extends UI{
	
	protected var oncheck:Function;
	protected var checked:int;
	
	public function List(data:Object,oncheck:Function,width:int,height:int,checked:int){
		this.oncheck=oncheck;
		this.checked=checked;
		createMouseWheel(this);
		createMouseOverOut(this);
		super(data,width,height);
		addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
		if(checked!=-1){
			setCheckedColor(0xf00000);
		}
	}
	
	protected function onMouseDown(event:MouseEvent):void{
		var lineIndex:int=getLineIndexAtMouse(this);
		if(lineIndex!=checked){
			if(checked!=-1){
				setCheckedColor(0x000000);
			}
			checked=lineIndex;
			if(checked!=-1){
				setCheckedColor(0xf00000);
				if(oncheck!=null){
					oncheck(checked);
				}
			}
		}
	}
	
	protected function setCheckedColor(color:int):void{
		textFormat.color=color;
		var start:int=getLineOffset(checked);
		var end:int=getLineLength(checked)+start;
		setTextFormat(textFormat,start,checked<(_data as Array).length-1?end-1:end);
	}
	
	override protected function updateText():void{
		text=(_data as Array).join("\n");
	}
}
class ComboBox extends Label{
	
	protected var lineIndex:int;
	protected var dropdown:List;
	protected var oncheck:Function;
	protected var checked:int;
	
	public function ComboBox(data:Object,oncheck:Function,checked:int,width:int,height:int){
		dropdown=new List(data,onDropdownCheck,width,14*10+4,lineIndex=checked);
		dropdown.addEventListener(MouseEvent.MOUSE_MOVE,onDropdownMouseMove);
		if(width<=0)dropdown.width+=20;
		this.oncheck=oncheck;
		this.checked=checked;
		createMouseOverOut(this);
		super(data,"L",width,height);
		addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
	}
	
	protected function onMouseDown(event:MouseEvent):void{
		event.stopImmediatePropagation();
		if(dropdown.parent!=null){
			onStageMouseDown(event);
		}
		else{
			var matrix:Matrix=transform.concatenatedMatrix;
			matrix.ty+=height+1;
			dropdown.transform.matrix=matrix;
			stage.addEventListener(MouseEvent.MOUSE_DOWN,onStageMouseDown);
			stage.addChild(dropdown);
			stage.focus=dropdown;
		}
	}

	protected function onStageMouseDown(event:MouseEvent):void{
		stage.removeEventListener(MouseEvent.MOUSE_DOWN,onStageMouseDown);
		stage.removeChild(dropdown);
	}
	
	protected function onDropdownMouseMove(event:MouseEvent):void{
		var line:int=getLineIndexAtMouse(dropdown);
		if(line!=lineIndex){
			lineIndex=line;
			var start:int=dropdown.getLineOffset(line);
			var end:int=dropdown.getLineLength(line)+start;
			dropdown.setSelection(start,line<(_data as Array).length-1?end-1:end);
		}
	}
	
	protected function onDropdownCheck(checked:int):void{
		this.checked=checked;
		updateText();
		updateSize();
		if(oncheck!=null){
			oncheck(checked);
		}
	}
	
	override protected function updateText():void{
		var data:Array=_data as Array;
		var checkedText:String=data[checked]+"\t\u2228";
		text=String(_height<=0||align=="T"?checkedText:"\n"+checkedText);
		textFormat.tabStops=[dropdown.width-16];
		setTextFormat(textFormat);
	}
	
	override protected function updateSize():void{
		if(_width<=0){
			_width=dropdown.width;
			super.updateSize();
			_width=0;
		}
		else{
			super.updateSize();
		}
	}
}
class Tree extends UI{
	
	protected var oncheck:Function;
	protected var checkedText:String;
	protected var checkedLine:int;
	protected var checkedStart:int;
	protected var checkedEnd:int;
	protected var expanded:Object;
	protected var expand:Boolean;
	protected var lineLength:int;
	protected var lineOffset:int;
	protected var spaces:Array=[];
	protected var texts:Array=[];
	protected var types:Array=[];
	protected var begins:Array=[];
	protected var ends:Array=[];
	protected var paths:Array=[];
	
	public function Tree(data:Object,oncheck:Function,width:int,height:int,expanded:Object){
		this.oncheck=oncheck;
		this.expanded=expanded;
		createMouseOverOut(this);
		createMouseWheel(this);
		super(data,width,height);
		addEventListener(TextEvent.LINK,onLink);
	}
	
	protected function onLink(event:TextEvent):void{
		var eventText:String=event.text;
		var type:int=int(eventText.charAt(0));
		var line:int=int(eventText.substring(1));
		var path:String=paths[line];
		if(type==0){
			if(checkedText!=path){
				checkedText=path;
				if(checkedLine!=-1){
					setFormat(0x000000,0,checkedLine,begins[checkedLine],ends[checkedLine]);
				}
				setFormat(0xf00000,0,checkedLine=line,begins[line],ends[line]);
				if(oncheck!=null){
					oncheck(path);
				}
			}
		}
		else{
			expanded[path]=type==2;
			updateText();
		}
	}
	
	protected function setFormat(color:int,type:int,line:int,begin:int,end:int):void{
		textFormat.color=color;
		textFormat.url="event:"+type+line;
		setTextFormat(textFormat,begin,end);
	}
	
	protected function updateTexts(file:Object,folder:String,indent:int):void{
		spaces.length=indent;
		var spaceText:String=spaces.join("    ");
		if(file is Array){
			var folderFiles:Array=file as Array;
			var folderName:String=folderFiles[0];
			folder=folder==null?folderName:folder+"/"+folderName;
			if(checkedText==folder)checkedLine=lineLength;
			lineOffset+=spaceText.length+3;
			begins[lineLength]=lineOffset;
			ends[lineLength]=(lineOffset+=folderName.length+1)-1;
			paths[lineLength]=folder;
			if(expand||expanded[folder]){
				indent++;
				types[lineLength]=1;
				texts[lineLength++]=spaceText+" \u2501 "+folderName;
				for(var i:int=1,n:int=folderFiles.length;i<n;i++){
					updateTexts(folderFiles[i],folder,indent);
				}
			}
			else{
				types[lineLength]=2;
				texts[lineLength++]=spaceText+" \u254b "+folderName;
			}
		}
		else{
			var fileName:String=file as String;
			folder=folder==null?fileName:folder+"/"+fileName;
			if(checkedText==folder)checkedLine=lineLength;
			lineOffset+=spaceText.length;
			begins[lineLength]=lineOffset;
			ends[lineLength]=(lineOffset+=fileName.length+1)-1;
			paths[lineLength]=folder;
			types[lineLength]=0;
			texts[lineLength++]=spaceText+fileName;
		}
	}
	
	override protected function updateText():void{
		checkedLine=-1;
		lineOffset=lineLength=0;
		var data:Array=_data as Array;
		for(var i:int=0;i<data.length;i++){
			updateTexts(data[i],null,1);
		}
		texts.length=lineLength;
		text=texts.join("\n");
		for(i=0;i<lineLength;i++){
			var type:int=types[i];
			var begin:int=begins[i];
			if(type>0)setFormat(type==1?0x808080:0x808000,type,i,begin-2,begin-1);
			setFormat(checkedLine==i?0xf00000:0x000000,0,i,begin,ends[i]);
		}
	}
	
	override protected function updateSize():void{
		var autoSize:Boolean=_width<=0||_height<=0;
		if(autoSize){
			expand=true;
			updateText();
		}
		super.updateSize();
		if(autoSize){
			expand=false;
			updateText();
		}
	}
}
